<!doctype html>
<!--
@license
Copyright (c) 2017 The Polymer Project Authors. All rights reserved.
This code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt
The complete set of authors may be found at http://polymer.github.io/AUTHORS.txt
The complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt
Code distributed by Google as part of the polymer project is also
subject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt
-->
<html>
<head>
  <meta charset="utf-8">
  <script>
    if (window.customElements) {
      customElements.forcePolyfill = true;
    }
    window.ShadyDOM = {
      force: true
    };
  </script>
  <script src="../../node_modules/@webcomponents/webcomponentsjs/webcomponents-bundle.js"></script>
  <script src="wct-browser-config.js"></script>
  <script src="../../node_modules/wct-browser-legacy/browser.js"></script>
  <script type="module" src="../../polymer-legacy.js"></script>
</head>
<body>

<dom-module id="x-dist">
  <template>
    x-dist
    <div id="distWrapper"><slot id="content"></slot></div>
  </template>
  <script type="module">
import { Polymer } from '../../polymer-legacy.js';
Polymer({is: 'x-dist'});
</script>
</dom-module>

<dom-module id="x-dist-simple">
  <template>
    <slot id="content"></slot>
  </template>
  <script type="module">
import { Polymer } from '../../polymer-legacy.js';
Polymer({is: 'x-dist-simple'});
</script>
</dom-module>

<dom-module id="x-dist-star">
  <template><slot></slot></template>
  <script type="module">
import { Polymer } from '../../polymer-legacy.js';
Polymer({is: 'x-dist-star'});
</script>
</dom-module>

<dom-module id="x-dist-inside-deep-tree">
  <template>
    x-dist-inside-deep-tree
    <div></div>
    <div>
      <div>
        <div>
          <div id="distWrapper"><slot id="content"></slot></div>
        </div>
      </div>
    </div>
    <div></div>
  </template>
  <script type="module">
import { Polymer } from '../../polymer-legacy.js';
Polymer({is: 'x-dist-inside-deep-tree'});
</script>
</dom-module>

<dom-module id="x-no-dist">
  <template><span id="static">x-no-dist</span></template>
  <script type="module">
import { Polymer } from '../../polymer-legacy.js';
Polymer({is: 'x-no-dist'});
</script>
</dom-module>

<dom-module id="x-compose-dist">
  <template>
    <x-dist id="dist"></x-dist>
  </template>
  <script type="module">
import { Polymer } from '../../polymer-legacy.js';
Polymer({is: 'x-compose-dist'});
</script>
</dom-module>

<dom-module id="x-compose-no-dist">
  <template>
    <x-no-dist id="noDist"></x-no-dist>
  </template>
  <script type="module">
import { Polymer } from '../../polymer-legacy.js';
Polymer({is: 'x-compose-no-dist'});
</script>
</dom-module>

<dom-module id="x-dynamic-content">
  <template>
    <div>
      <div>
        <div>
          <div id="container">
            <template is="dom-if" id="domif">
              <slot name="insert" id="dynamicContent"></slot>
            </template>
          </div>
        </div>
      </div>
    </div>
  </template>
  <script type="module">
import { Polymer } from '../../polymer-legacy.js';
Polymer({is: 'x-dynamic-content'});
</script>
</dom-module>

<dom-module id="x-dynamic-content-wrapped">
  <template>
    <div>
      <template is="dom-if" id="domif">
        <div id="container">
          <slot name="insert"></slot>
        </div>
      </template>
    </div>
  </template>
  <script type="module">
import { Polymer } from '../../polymer-legacy.js';
Polymer({is: 'x-dynamic-content-wrapped'});
</script>
</dom-module>

<dom-module id="x-dynamic-content-redist">
  <template>
    <x-dynamic-content id="redistContainer">
      <template is="dom-if" id="redistDomif">
        <slot name="insert" id="redistContent"></slot>
      </template>
    </x-dynamic-content>
  </template>
  <script type="module">
import { Polymer } from '../../polymer-legacy.js';
Polymer({is: 'x-dynamic-content-redist'});
</script>
</dom-module>

<dom-module id="x-dynamic-content-redist-element">
  <template>
    <template is="dom-if" id="redistDomif">
      <x-dist id="redistContainer">
        <slot name="insert" id="redistContent"></slot>
      </x-dist>
    </template>
  </template>
  <script type="module">
import { Polymer } from '../../polymer-legacy.js';
Polymer({is: 'x-dynamic-content-redist-element'});
</script>
</dom-module>

<dom-module id="x-dynamic-content-and-dynamic-no-content">
  <template>
    <div id="container">
      <template is="dom-if" id="staticIf" restamp>
        <div id="static">static</div>
      </template>
      <template is="dom-if" id="contentIf" restamp>
        <slot name="one"></slot>
      </template>
    </div>
  </template>
  <script type="module">
import { Polymer } from '../../polymer-legacy.js';
Polymer({is: 'x-dynamic-content-and-dynamic-no-content'});
</script>
</dom-module>

<dom-module id="x-multi-dist">
  <template>
    <x-dist id="dist1"><slot id="content1"></slot></x-dist>
    <x-dist id="dist2"><slot id="content2"></slot></x-dist>
  </template>
  <script type="module">
import { Polymer } from '../../polymer-legacy.js';
Polymer({is: 'x-multi-dist'});
</script>
</dom-module>

<dom-module id="x-lazy-no-dist">
  <template>
    Lazy no dist!
  </template>
</dom-module>

<dom-module id="x-compose-lazy-no-dist">
  <template>
    <x-lazy-no-dist id="lazy">
      <slot></slot>
    </x-lazy-no-dist>
  </template>
  <script type="module">
import { Polymer } from '../../polymer-legacy.js';
Polymer({is: 'x-compose-lazy-no-dist'});
</script>
</dom-module>

<dom-module id="x-toggle-if">
  <template>
    <div id="container1">
      <template id="foo" is="dom-if" if="{{foo}}" restamp>
        <span>foo</span>
        <slot id="1.1" name="one"></slot>
        <slot id="1.2" name="two"></slot>
      </template>
    </div>
    <div id="container2">
      <template id="notFoo" is="dom-if" if="{{!foo}}" restamp>
        <span>Not foo</span>
        <slot id="2.1" name="one"></slot>
        <slot id="2.2" name="two"></slot>
      </template>
    </div>
  </template>
  <script type="module">
import { Polymer } from '../../polymer-legacy.js';
Polymer({
  is: 'x-toggle-if',
  properties: {
    foo: {
      type: Boolean,
      value: true
    }
  }
});
</script>
</dom-module>

<dom-module id="x-repeat">
  <template>
    <x-dist-inside-deep-tree id="dist">
      <template is="dom-repeat" items="{{items}}"><div>{{item}}</div></template>
    </x-dist-inside-deep-tree>
  </template>
  <script type="module">
import { Polymer } from '../../polymer-legacy.js';
Polymer({
  is: 'x-repeat',
  properties: {
    items: {
      type: Array,
      value: ["ITEM1", "ITEM2", "ITEM3"]
    }
  }
});
</script>
</dom-module>

<dom-module id="x-repeat2">
  <template>
    <x-dist-star id="dist">
      <template is="dom-repeat" items="{{items}}">
        <div>{{item}}</div>
      </template>
    </x-dist-star>
  </template>
  <script type="module">
import { Polymer } from '../../polymer-legacy.js';
Polymer({
  is: 'x-repeat2',
  properties: {
    items: {
      type: Array,
      value: ["ITEM1", "ITEM2", "ITEM3"]
    }
  }
});
</script>
</dom-module>

<x-repeat2 id="repeat2"></x-repeat2>

<x-compose-lazy-no-dist><span>Child</span></x-compose-lazy-no-dist>

<script>
  if (!window.ShadyDOM) {
    ShadyDOM = {
      patch: function() {},
      flush: function() {}
    };
  }
</script>
<script type="module">
import { Polymer } from '../../polymer-legacy.js';
import { flush } from '../../lib/utils/flush.js';
function createPatchedDocumentFragment() {
  var frag = document.createDocumentFragment();
  return frag;
}

suite('appendChild & removeChild of <slot>', function() {

  test('append div to distributing element', function() {
    var dist = document.createElement('x-dist');
    document.body.appendChild(dist);
    // Distribute div
    var div = document.createElement('div');
    dist.appendChild(div);
    ShadyDOM.flush();
    // Append to distributed div
    var div2 = document.createElement('div');
    div.appendChild(div2);
    ShadyDOM.flush();
    // Remove
    dist.removeChild(div);
    ShadyDOM.flush();
    document.body.removeChild(dist);
  });

  test('append div to non-distributing element', function() {
    var noDist = document.createElement('x-no-dist');
    document.body.appendChild(noDist);
    // Distribute div
    var div = document.createElement('div');
    noDist.appendChild(div);
    ShadyDOM.flush();
    // Append to distributed div
    var div2 = document.createElement('div');
    div.appendChild(div2);
    ShadyDOM.flush();
    // Remove
    noDist.removeChild(div);
    ShadyDOM.flush();
    document.body.removeChild(noDist);
  });

  test('append div to shady root of distributing element', function() {
    var dist = document.createElement('x-dist');
    document.body.appendChild(dist);
    // Append div to root
    var div = document.createElement('div');
    dist.root.appendChild(div);
    ShadyDOM.flush();
    // Append to div in root
    var div2 = document.createElement('div');
    div.appendChild(div2);
    ShadyDOM.flush();
    // Remove
    dist.root.removeChild(div);
    ShadyDOM.flush();
    document.body.removeChild(dist);
  });

  test('append div to shady root of non-distributing element', function() {
    var noDist = document.createElement('x-no-dist');
    document.body.appendChild(noDist);
    // Append div to root
    var div = document.createElement('div');
    noDist.root.appendChild(div);
    ShadyDOM.flush();
    // Append to div in root
    var div2 = document.createElement('div');
    div.appendChild(div2);
    ShadyDOM.flush();
    // Remove
    noDist.root.removeChild(div);
    ShadyDOM.flush();
    document.body.removeChild(noDist);
  });

  test('append div to distributing element in root', function() {
    var compose = document.createElement('x-compose-dist');
    document.body.appendChild(compose);
    // Distribute div
    var div = document.createElement('div');
    compose.$.dist.appendChild(div);
    ShadyDOM.flush();
    // Append to distributed div
    var div2 = document.createElement('div');
    div.appendChild(div2);
    ShadyDOM.flush();
    // Remove
    compose.$.dist.removeChild(div);
    ShadyDOM.flush();
    document.body.removeChild(compose);
  });

  test('append div to non-distributing element in root', function() {
    var compose = document.createElement('x-compose-no-dist');
    document.body.appendChild(compose);
    // Append div to root
    var div = document.createElement('div');
    compose.$.noDist.appendChild(div);
    ShadyDOM.flush();
    // Append to div in root
    var div2 = document.createElement('div');
    div.appendChild(div2);
    ShadyDOM.flush();
    // Remove
    compose.$.noDist.removeChild(div);
    ShadyDOM.flush();
    document.body.removeChild(compose);
  });

  test('append slot to shady root of element (div first)', function() {
    var noDist = document.createElement('x-no-dist');
    document.body.appendChild(noDist);
    // Append div to light dom
    var div = document.createElement('div');
    div.name = 'insert';
    noDist.appendChild(div);
    ShadyDOM.flush();
    // Append slot to shady root
    var slot = document.createElement('slot');
    slot.setAttribute('name', 'insert');
    noDist.root.appendChild(slot);
    ShadyDOM.flush();
    // Remove
    noDist.root.removeChild(slot);
    ShadyDOM.flush();
    document.body.removeChild(noDist);
  });

  test('append slot to shady root of element (slot first)', function() {
    var noDist = document.createElement('x-no-dist');
    document.body.appendChild(noDist);
    // Append slot to shady root
    var slot = document.createElement('slot');
    slot.setAttribute('name', 'insert');
    noDist.root.appendChild(slot);
    // Append div to light dom
    var div = document.createElement('div');
    div.name = 'insert';
    noDist.appendChild(div);
    ShadyDOM.flush();
    // Remove
    noDist.root.removeChild(slot);
    ShadyDOM.flush();
    document.body.removeChild(noDist);
  });

  test('append slot to div in shady root of element (div first)', function() {
    var noDist = document.createElement('x-no-dist');
    document.body.appendChild(noDist);
    // Append div to light dom
    var div = document.createElement('div');
    div.name = 'insert';
    noDist.appendChild(div);
    ShadyDOM.flush();
    // Append slot to shady root
    var slot = document.createElement('slot');
    slot.setAttribute('name', 'insert');
    noDist.$.static.appendChild(slot);
    ShadyDOM.flush();
    // Remove
    noDist.$.static.removeChild(slot);
    ShadyDOM.flush();
    document.body.removeChild(noDist);
  });

  test('append slot to div in shady root of element (slot first)', function() {
    var noDist = document.createElement('x-no-dist');
    document.body.appendChild(noDist);
    // Append slot to shady root
    var slot = document.createElement('slot');
    slot.setAttribute('name', 'insert');
    noDist.$.static.appendChild(slot);
    // Append div to light dom
    var div = document.createElement('div');
    div.name = 'insert';
    noDist.appendChild(div);
    ShadyDOM.flush();
    // Remove
    noDist.$.static.removeChild(slot);
    ShadyDOM.flush();
    document.body.removeChild(noDist);
  });

  test('append slot in fragment to shady root of element (div first)', function() {
    var noDist = document.createElement('x-no-dist');
    document.body.appendChild(noDist);
    // Append div to light dom
    var div = document.createElement('div');
    div.name = 'insert';
    noDist.appendChild(div);
    ShadyDOM.flush();
    // Append slot to shady root
    var frag = document.createDocumentFragment();
    var slot = document.createElement('slot');
    slot.setAttribute('name', 'insert');
    frag.appendChild(slot);
    noDist.root.appendChild(frag);
    ShadyDOM.flush();
    // Remove
    noDist.root.removeChild(slot);
    ShadyDOM.flush();
    document.body.removeChild(noDist);
  });

  test('append slot in fragment to shady root of element (slot first)', function() {
    var noDist = document.createElement('x-no-dist');
    document.body.appendChild(noDist);
    // Append slot to shady root
    var frag = document.createDocumentFragment();
    var slot = document.createElement('slot');
    slot.setAttribute('name', 'insert');
    frag.appendChild(slot);
    noDist.root.appendChild(frag);
    // Append div to light dom
    var div = document.createElement('div');
    div.name = 'insert';
    noDist.appendChild(div);
    ShadyDOM.flush();

    // Remove
    noDist.root.removeChild(slot);
    ShadyDOM.flush();

    document.body.removeChild(noDist);
  });

  test('append wrapped slot to shady root of element (div first)', function() {
    var noDist = document.createElement('x-no-dist');
    document.body.appendChild(noDist);
    // Append div to light dom
    var div = document.createElement('div');
    div.name = 'insert';
    noDist.appendChild(div);
    ShadyDOM.flush();
    // Append slot to shady root
    var frag = document.createDocumentFragment();
    var wrapper = document.createElement('div');
    var slot = document.createElement('slot');
    slot.setAttribute('name', 'insert');
    wrapper.appendChild(slot);
    frag.appendChild(wrapper);
    noDist.root.appendChild(frag);
    ShadyDOM.flush();

    // Remove
    noDist.root.removeChild(wrapper);
    ShadyDOM.flush();

    document.body.removeChild(noDist);
  });

  test('append wrapped slot to shady root of element (slot first)', function() {
    var noDist = document.createElement('x-no-dist');
    document.body.appendChild(noDist);
    // Append slot to shady root
    var frag = document.createDocumentFragment();
    var wrapper = document.createElement('div');
    var slot = document.createElement('slot');
    slot.setAttribute('name', 'insert');
    wrapper.appendChild(slot);
    frag.appendChild(wrapper);
    noDist.root.appendChild(frag);
    // Append div to light dom
    var div = document.createElement('div');
    div.name = 'insert';
    noDist.appendChild(div);
    ShadyDOM.flush();

    // Remove
    noDist.root.removeChild(wrapper);
    ShadyDOM.flush();

    document.body.removeChild(noDist);
  });

  test('append wrapped slot to div in shady root of element (div first)', function() {
    var noDist = document.createElement('x-no-dist');
    document.body.appendChild(noDist);
    // Append div to light dom
    var div = document.createElement('div');
    div.name = 'insert';
    noDist.appendChild(div);
    ShadyDOM.flush();
    // Append slot to shady root
    var frag = document.createDocumentFragment();
    var wrapper = document.createElement('div');
    var slot = document.createElement('slot');
    slot.setAttribute('name', 'insert');
    wrapper.appendChild(slot);
    frag.appendChild(wrapper);
    noDist.$.static.appendChild(frag);
    ShadyDOM.flush();

    // Remove
    noDist.$.static.removeChild(wrapper);
    ShadyDOM.flush();

    document.body.removeChild(noDist);
  });

  test('append wrapped slot to div in shady root of element (slot first)', function() {
    var noDist = document.createElement('x-no-dist');
    document.body.appendChild(noDist);
    // Append slot to shady root
    var frag = document.createDocumentFragment();
    var wrapper = document.createElement('div');
    var slot = document.createElement('slot');
    slot.setAttribute('name', 'insert');
    wrapper.appendChild(slot);
    frag.appendChild(wrapper);
    noDist.$.static.appendChild(frag);
    // Append div to light dom
    var div = document.createElement('div');
    div.name = 'insert';
    noDist.appendChild(div);
    ShadyDOM.flush();

    // Remove
    noDist.$.static.removeChild(wrapper);
    ShadyDOM.flush();

    document.body.removeChild(noDist);
  });

  test('append slot to non-distributing element in shady root of composed element (div first)', function() {
    var compose = document.createElement('x-compose-no-dist');
    document.body.appendChild(compose);
    // Append slot to light DOM of non-distributing element
    var div = document.createElement('div');
    div.name = 'insert';
    compose.appendChild(div);
    ShadyDOM.flush();
    // Append slot to non-distributing element
    var slot = document.createElement('slot');
    slot.setAttribute('name', 'insert');
    compose.$.noDist.appendChild(slot);
    ShadyDOM.flush();

    // Remove
    compose.$.noDist.removeChild(slot);
    ShadyDOM.flush();

    document.body.removeChild(compose);
  });

  test('append slot to non-distributing element in shady root of composed element (slot first)', function() {
    var compose = document.createElement('x-compose-no-dist');
    document.body.appendChild(compose);
    // Append slot to light DOM of non-distributing element
    var slot = document.createElement('slot');
    slot.setAttribute('name', 'insert');
    compose.$.noDist.appendChild(slot);
    // Append div to light dom
    var div = document.createElement('div');
    div.name = 'insert';
    compose.appendChild(div);
    ShadyDOM.flush();

    // Remove
    compose.$.noDist.removeChild(slot);
    ShadyDOM.flush();

    document.body.removeChild(compose);
  });

  test('append wrapped slot to non-distributing element in shady root of composed element (div first)', function() {
    var compose = document.createElement('x-compose-no-dist');
    document.body.appendChild(compose);
    // Append div to light dom
    var div = document.createElement('div');
    div.name = 'insert';
    compose.appendChild(div);
    ShadyDOM.flush();
    // Append slot to shady root
    var frag = document.createDocumentFragment();
    var wrapper = document.createElement('div');
    var slot = document.createElement('slot');
    slot.setAttribute('name', 'insert');
    wrapper.appendChild(slot);
    frag.appendChild(wrapper);
    compose.$.noDist.appendChild(frag);
    ShadyDOM.flush();

    // Remove
    compose.$.noDist.removeChild(wrapper);
    ShadyDOM.flush();

    document.body.removeChild(compose);
  });

  test('append wrapped slot to non-distributing element in shady root of composed element (slot first)', function() {
    var compose = document.createElement('x-compose-no-dist');
    document.body.appendChild(compose);
    // Append slot to shady root
    var frag = document.createDocumentFragment();
    var wrapper = document.createElement('div');
    var slot = document.createElement('slot');
    slot.setAttribute('name', 'insert');
    wrapper.appendChild(slot);
    frag.appendChild(wrapper);
    compose.$.noDist.appendChild(frag);
    // Append div to light dom
    var div = document.createElement('div');
    div.name = 'insert';
    compose.appendChild(div);
    ShadyDOM.flush();

    // Remove
    compose.$.noDist.removeChild(wrapper);
    ShadyDOM.flush();

    document.body.removeChild(compose);
  });

  test('append slot to distributing element in shady root of composed element (div first)', function() {
    var compose = document.createElement('x-compose-dist');
    document.body.appendChild(compose);
    // Append slot to light DOM of non-distributing element
    var div = document.createElement('div');
    div.name = 'insert';
    compose.appendChild(div);
    ShadyDOM.flush();
    // Append slot to non-distributing element
    var slot = document.createElement('slot');
    slot.setAttribute('name', 'insert');
    compose.$.dist.appendChild(slot);
    ShadyDOM.flush();

    // Remove
    compose.$.dist.removeChild(slot);
    ShadyDOM.flush();

    document.body.removeChild(compose);
  });

  test('append slot to distributing element in shady root of composed element (slot first)', function() {
    var compose = document.createElement('x-compose-dist');
    document.body.appendChild(compose);
    // Append slot to non-distributing element
    var slot = document.createElement('slot');
    slot.setAttribute('name', 'insert');
    compose.$.dist.appendChild(slot);
    // Append slot to light DOM of non-distributing element
    var div = document.createElement('div');
    div.name = 'insert';
    compose.appendChild(div);
    ShadyDOM.flush();

    // Remove
    compose.$.dist.removeChild(slot);
    ShadyDOM.flush();

    document.body.removeChild(compose);
  });

  test('append wrapped slot to distributing element in shady root of composed element (div first)', function() {
    var compose = document.createElement('x-compose-dist');
    document.body.appendChild(compose);
    // Append div to light dom
    var div = document.createElement('div');
    div.name = 'insert';
    compose.appendChild(div);
    ShadyDOM.flush();
    // Append slot to shady root
    var frag = document.createDocumentFragment();
    var wrapper = document.createElement('div');
    var slot = document.createElement('slot');
    slot.setAttribute('name', 'insert');
    wrapper.appendChild(slot);
    frag.appendChild(wrapper);
    compose.$.dist.appendChild(frag);
    ShadyDOM.flush();

    // Remove
    compose.$.dist.removeChild(wrapper);
    ShadyDOM.flush();

    document.body.removeChild(compose);
  });

  test('append wrapped slot to distributing element in shady root of composed element (slot first)', function() {
    var compose = document.createElement('x-compose-dist');
    document.body.appendChild(compose);
    // Append slot to shady root
    var frag = document.createDocumentFragment();
    var wrapper = document.createElement('div');
    var slot = document.createElement('slot');
    slot.setAttribute('name', 'insert');
    wrapper.appendChild(slot);
    frag.appendChild(wrapper);
    compose.$.dist.appendChild(frag);
    // Append div to light dom
    var div = document.createElement('div');
    div.name = 'insert';
    compose.appendChild(div);
    ShadyDOM.flush();

    // Remove
    compose.$.dist.removeChild(wrapper);
    ShadyDOM.flush();

    document.body.removeChild(compose);
  });

  test('append slot to initially un-upgraded element', function() {
    var lazyContainer = document.querySelector('x-compose-lazy-no-dist');
    var child = lazyContainer.firstElementChild;
    Polymer({is: 'x-lazy-no-dist'});
    var slot = document.createElement('slot');
    lazyContainer.$.lazy.root.appendChild(slot);
    ShadyDOM.flush();
    assert.equal(slot.assignedNodes({flatten: true})[1], child);

  });

  test('composed children distributed', function() {
    var host = document.createElement('x-dist');
    document.body.appendChild(host);
    var s0 = document.createElement('span');
    var frag = document.createDocumentFragment();
    var s1 = document.createElement('span');
    var s2 = document.createElement('span');
    var s3 = document.createElement('span');
    frag.appendChild(s1);
    frag.appendChild(s2);
    frag.appendChild(s3);
    host.appendChild(s0);
    host.insertBefore(frag, s0);
    ShadyDOM.flush();

    host.removeChild(s1);
    host.removeChild(s2);
    host.removeChild(s3);
    ShadyDOM.flush();

  });

  test('composed children added but not distributed', function() {
    var host = document.createElement('x-dist');
    document.body.appendChild(host);
    var s0 = document.createElement('span');
    var frag = document.createDocumentFragment();
    var s1 = document.createElement('span');
    var s2 = document.createElement('span');
    var s3 = document.createElement('span');
    frag.appendChild(s1);
    frag.appendChild(s2);
    frag.appendChild(s3);
    host.$.distWrapper.appendChild(s0);
    host.$.distWrapper.insertBefore(frag, s0);
    ShadyDOM.flush();

    host.$.distWrapper.removeChild(s1);
    host.$.distWrapper.removeChild(s2);
    host.$.distWrapper.removeChild(s3);
    ShadyDOM.flush();

  });

  test('moving children between distributing hosts', function() {
    var h1 = document.createElement('x-dist');
    var h2 = document.createElement('x-dist');
    document.body.appendChild(h1);
    document.body.appendChild(h2);
    ShadyDOM.flush();
    var d = document.createElement('div');
    h1.appendChild(d);
    ShadyDOM.flush();
    assert.equal(h1.childNodes.length, 1);
    assert.equal(h1.firstElementChild, d);
    assert.deepEqual(h1.$.content.assignedNodes({flatten: true}), [d]);
    assert.equal(h2.childNodes.length, 0);
    assert.deepEqual(h2.$.content.assignedNodes({flatten: true}).length, 0);
    h2.appendChild(d);
    ShadyDOM.flush();
    assert.equal(h2.childNodes.length, 1);
    assert.equal(h2.firstElementChild, d);
    assert.deepEqual(h2.$.content.assignedNodes({flatten: true}), [d]);
    assert.equal(h1.childNodes.length, 0);
    assert.deepEqual(h1.$.content.assignedNodes({flatten: true}).length, 0);
    h1.appendChild(d);
    ShadyDOM.flush();
    assert.equal(h1.childNodes.length, 1);
    assert.equal(h1.firstElementChild, d);
    assert.deepEqual(h1.$.content.assignedNodes({flatten: true}), [d]);
    assert.equal(h2.childNodes.length, 0);
    assert.deepEqual(h2.$.content.assignedNodes({flatten: true}).length, 0);
    h2.appendChild(d);
    ShadyDOM.flush();
    assert.equal(h2.childNodes.length, 1);
    assert.equal(h2.firstElementChild, d);
    assert.deepEqual(h2.$.content.assignedNodes({flatten: true}), [d]);
    assert.equal(h1.childNodes.length, 0);
    assert.deepEqual(h1.$.content.assignedNodes({flatten: true}).length, 0);
    document.body.removeChild(h1);
    document.body.removeChild(h2);
  });

  test('moving children between distributing hosts (parsed child)', function() {
    var div = document.createElement('div');
    div.innerHTML = '<x-dist><div></div></x-dist>';
    var h1 = div.firstChild;
    var h2 = document.createElement('x-dist');
    document.body.appendChild(div);
    document.body.appendChild(h2);
    ShadyDOM.flush();
    var d = h1.firstElementChild;
    assert.equal(d.localName, 'div');
    assert.equal(h1.childNodes.length, 1);
    assert.equal(h1.firstElementChild, d);
    assert.deepEqual(h1.$.content.assignedNodes({flatten: true}), [d]);
    assert.equal(h2.childNodes.length, 0);
    assert.deepEqual(h2.$.content.assignedNodes({flatten: true}).length, 0);
    h2.appendChild(d);
    ShadyDOM.flush();
    assert.equal(h2.childNodes.length, 1);
    assert.equal(h2.firstElementChild, d);
    assert.deepEqual(h2.$.content.assignedNodes({flatten: true}), [d]);
    assert.equal(h1.childNodes.length, 0);
    assert.deepEqual(h1.$.content.assignedNodes({flatten: true}).length, 0);
    h1.appendChild(d);
    ShadyDOM.flush();
    assert.equal(h1.childNodes.length, 1);
    assert.equal(h1.firstElementChild, d);
    assert.deepEqual(h1.$.content.assignedNodes({flatten: true}), [d]);
    assert.equal(h2.childNodes.length, 0);
    assert.deepEqual(h2.$.content.assignedNodes({flatten: true}).length, 0);
    h2.appendChild(d);
    ShadyDOM.flush();
    assert.equal(h2.childNodes.length, 1);
    assert.equal(h2.firstElementChild, d);
    assert.deepEqual(h2.$.content.assignedNodes({flatten: true}), [d]);
    assert.equal(h1.childNodes.length, 0);
    assert.deepEqual(h1.$.content.assignedNodes({flatten: true}).length, 0);
    document.body.removeChild(div);
    document.body.removeChild(h2);
  });

  test('moving children between distributing host and fragment', function() {
    var h1 = document.createElement('x-dist');
    var h2 = createPatchedDocumentFragment();
    document.body.appendChild(h1);
    ShadyDOM.flush();
    var d = document.createElement('div');
    h1.appendChild(d);
    ShadyDOM.flush();
    assert.equal(h1.childNodes.length, 1);
    assert.equal(h1.firstElementChild, d);
    assert.deepEqual(h1.$.content.assignedNodes({flatten: true}), [d]);
    assert.equal(h2.childNodes.length, 0);
    h2.appendChild(d);
    ShadyDOM.flush();
    assert.equal(h2.childNodes.length, 1);
    assert.equal(h2.firstChild, d);
    assert.equal(h1.childNodes.length, 0);
    assert.deepEqual(h1.$.content.assignedNodes({flatten: true}).length, 0);
    h1.appendChild(d);
    ShadyDOM.flush();
    assert.equal(h1.childNodes.length, 1);
    assert.equal(h1.firstElementChild, d);
    assert.deepEqual(h1.$.content.assignedNodes({flatten: true}), [d]);
    assert.equal(h2.childNodes.length, 0);
    h2.appendChild(d);
    ShadyDOM.flush();
    assert.equal(h2.childNodes.length, 1);
    assert.equal(h2.firstChild, d);
    assert.equal(h1.childNodes.length, 0);
    assert.deepEqual(h1.$.content.assignedNodes({flatten: true}).length, 0);
    document.body.removeChild(h1);
  });

  test('moving children between distributing host and fragment (parsed child)', function() {
    var div = document.createElement('div');
    div.innerHTML = '<x-dist><div></div></x-dist>';
    var h1 = div.firstChild;
    var h2 = createPatchedDocumentFragment();
    document.body.appendChild(h1);
    ShadyDOM.flush();
    var d = h1.firstElementChild;
    assert.equal(d.localName, 'div');
    assert.equal(h1.childNodes.length, 1);
    assert.equal(h1.firstElementChild, d);
    assert.deepEqual(h1.$.content.assignedNodes({flatten: true}), [d]);
    assert.equal(h2.childNodes.length, 0);
    h2.appendChild(d);
    ShadyDOM.flush();
    assert.equal(h2.childNodes.length, 1);
    assert.equal(h2.firstChild, d);
    assert.equal(h1.childNodes.length, 0);
    assert.deepEqual(h1.$.content.assignedNodes({flatten: true}).length, 0);
    h1.appendChild(d);
    ShadyDOM.flush();
    assert.equal(h1.childNodes.length, 1);
    assert.equal(h1.firstElementChild, d);
    assert.deepEqual(h1.$.content.assignedNodes({flatten: true}), [d]);
    assert.equal(h2.childNodes.length, 0);
    h2.appendChild(d);
    ShadyDOM.flush();
    assert.equal(h2.childNodes.length, 1);
    assert.equal(h2.firstChild, d);
    assert.equal(h1.childNodes.length, 0);
    assert.deepEqual(h1.$.content.assignedNodes({flatten: true}).length, 0);
    document.body.removeChild(h1);
  });

  test('moving children between distributing hosts with deep insertion points', function() {
    var h1 = document.createElement('x-dist-inside-deep-tree');
    var h2 = document.createElement('x-dist-inside-deep-tree');
    document.body.appendChild(h1);
    document.body.appendChild(h2);
    ShadyDOM.flush();
    var d = document.createElement('div');
    h1.appendChild(d);
    ShadyDOM.flush();
    assert.equal(h1.childNodes.length, 1);
    assert.equal(h1.firstElementChild, d);
    assert.deepEqual(h1.$.content.assignedNodes({flatten: true}), [d]);
    assert.equal(h2.childNodes.length, 0);
    assert.deepEqual(h2.$.content.assignedNodes({flatten: true}).length, 0);
    h2.appendChild(d);
    ShadyDOM.flush();
    assert.equal(h2.childNodes.length, 1);
    assert.equal(h2.firstElementChild, d);
    assert.deepEqual(h2.$.content.assignedNodes({flatten: true}), [d]);
    assert.equal(h1.childNodes.length, 0);
    assert.deepEqual(h1.$.content.assignedNodes({flatten: true}).length, 0);
    h1.appendChild(d);
    ShadyDOM.flush();
    assert.equal(h1.childNodes.length, 1);
    assert.equal(h1.firstElementChild, d);
    assert.deepEqual(h1.$.content.assignedNodes({flatten: true}), [d]);
    assert.equal(h2.childNodes.length, 0);
    assert.deepEqual(h2.$.content.assignedNodes({flatten: true}).length, 0);
    h2.appendChild(d);
    ShadyDOM.flush();
    assert.equal(h2.childNodes.length, 1);
    assert.equal(h2.firstElementChild, d);
    assert.deepEqual(h2.$.content.assignedNodes({flatten: true}), [d]);
    assert.equal(h1.childNodes.length, 0);
    assert.deepEqual(h1.$.content.assignedNodes({flatten: true}).length, 0);
    document.body.removeChild(h1);
    document.body.removeChild(h2);
  });

  test('moving children between distributing hosts with deep insertion points (parsed child)', function() {
    var div = document.createElement('div');
    div.innerHTML = '<x-dist-inside-deep-tree><div></div></x-dist-inside-deep-tree>';
    var h1 = div.firstChild;
    var h2 = document.createElement('x-dist-inside-deep-tree');
    document.body.appendChild(div);
    document.body.appendChild(h2);
    ShadyDOM.flush();
    var d = h1.firstElementChild;
    assert.equal(d.localName, 'div');
    assert.equal(h1.childNodes.length, 1);
    assert.equal(h1.firstElementChild, d);
    assert.deepEqual(h1.$.content.assignedNodes({flatten: true}), [d]);
    assert.equal(h2.childNodes.length, 0);
    assert.deepEqual(h2.$.content.assignedNodes({flatten: true}).length, 0);
    h2.appendChild(d);
    ShadyDOM.flush();
    assert.equal(h2.childNodes.length, 1);
    assert.equal(h2.firstElementChild, d);
    assert.deepEqual(h2.$.content.assignedNodes({flatten: true}), [d]);
    assert.equal(h1.childNodes.length, 0);
    assert.deepEqual(h1.$.content.assignedNodes({flatten: true}).length, 0);
    h1.appendChild(d);
    ShadyDOM.flush();
    assert.equal(h1.childNodes.length, 1);
    assert.equal(h1.firstElementChild, d);
    assert.deepEqual(h1.$.content.assignedNodes({flatten: true}), [d]);
    assert.equal(h2.childNodes.length, 0);
    assert.deepEqual(h2.$.content.assignedNodes({flatten: true}).length, 0);
    h2.appendChild(d);
    ShadyDOM.flush();
    assert.equal(h2.childNodes.length, 1);
    assert.equal(h2.firstElementChild, d);
    assert.deepEqual(h2.$.content.assignedNodes({flatten: true}), [d]);
    assert.equal(h1.childNodes.length, 0);
    assert.deepEqual(h1.$.content.assignedNodes({flatten: true}).length, 0);
    document.body.removeChild(div);
    document.body.removeChild(h2);
  });

  test('moving children between distributing host with deep insertion and fragment', function() {
    var h1 = document.createElement('x-dist-inside-deep-tree');
    var h2 = createPatchedDocumentFragment();
    document.body.appendChild(h1);
    ShadyDOM.flush();
    var d = document.createElement('div');
    h1.appendChild(d);
    ShadyDOM.flush();
    assert.equal(h1.childNodes.length, 1);
    assert.equal(h1.firstElementChild, d);
    assert.deepEqual(h1.$.content.assignedNodes({flatten: true}), [d]);
    assert.equal(h2.childNodes.length, 0);
    h2.appendChild(d);
    ShadyDOM.flush();
    assert.equal(h2.childNodes.length, 1);
    assert.equal(h2.firstChild, d);
    assert.equal(h1.childNodes.length, 0);
    assert.deepEqual(h1.$.content.assignedNodes({flatten: true}).length, 0);
    h1.appendChild(d);
    ShadyDOM.flush();
    assert.equal(h1.childNodes.length, 1);
    assert.equal(h1.firstElementChild, d);
    assert.deepEqual(h1.$.content.assignedNodes({flatten: true}), [d]);
    assert.equal(h2.childNodes.length, 0);
    h2.appendChild(d);
    ShadyDOM.flush();
    assert.equal(h2.childNodes.length, 1);
    assert.equal(h2.firstChild, d);
    assert.equal(h1.childNodes.length, 0);
    assert.deepEqual(h1.$.content.assignedNodes({flatten: true}).length, 0);
    document.body.removeChild(h1);
  });

  test('moving children between distributing host with deep insertion and fragment (parsed child)', function() {
    var div = document.createElement('div');
    div.innerHTML = '<x-dist-inside-deep-tree><div></div></x-dist-inside-deep-tree>';
    var h1 = div.firstChild;
    var h2 = createPatchedDocumentFragment();
    document.body.appendChild(h1);
    ShadyDOM.flush();
    var d = h1.firstElementChild;
    assert.equal(d.localName, 'div');
    assert.equal(h1.childNodes.length, 1);
    assert.equal(h1.firstElementChild, d);
    assert.deepEqual(h1.$.content.assignedNodes({flatten: true}), [d]);
    assert.equal(h2.childNodes.length, 0);
    h2.appendChild(d);
    ShadyDOM.flush();
    assert.equal(h2.childNodes.length, 1);
    assert.equal(h2.firstChild, d);
    assert.equal(h1.childNodes.length, 0);
    assert.deepEqual(h1.$.content.assignedNodes({flatten: true}).length, 0);
    h1.appendChild(d);
    ShadyDOM.flush();
    assert.equal(h1.childNodes.length, 1);
    assert.equal(h1.firstElementChild, d);
    assert.deepEqual(h1.$.content.assignedNodes({flatten: true}), [d]);
    assert.equal(h2.childNodes.length, 0);
    h2.appendChild(d);
    ShadyDOM.flush();
    assert.equal(h2.childNodes.length, 1);
    assert.equal(h2.firstChild, d);
    assert.equal(h1.childNodes.length, 0);
    assert.deepEqual(h1.$.content.assignedNodes({flatten: true}).length, 0);
    document.body.removeChild(h1);
  });

  test('moving children between distributing host with shallow insertion and fragment', function() {
    var h1 = document.createElement('x-dist-simple');
    var h2 = createPatchedDocumentFragment();
    document.body.appendChild(h1);
    ShadyDOM.flush();
    var d = document.createElement('div');
    h1.appendChild(d);
    ShadyDOM.flush();
    assert.equal(h1.childNodes.length, 1);
    assert.equal(h1.firstElementChild, d);
    assert.deepEqual(h1.$.content.assignedNodes({flatten: true}), [d]);
    assert.equal(h2.childNodes.length, 0);
    h2.appendChild(d);
    ShadyDOM.flush();
    assert.equal(h2.childNodes.length, 1);
    assert.equal(h2.firstChild, d);
    assert.equal(h1.childNodes.length, 0);
    assert.deepEqual(h1.$.content.assignedNodes({flatten: true}).length, 0);
    h1.appendChild(d);
    ShadyDOM.flush();
    assert.equal(h1.childNodes.length, 1);
    assert.equal(h1.firstElementChild, d);
    assert.deepEqual(h1.$.content.assignedNodes({flatten: true}), [d]);
    assert.equal(h2.childNodes.length, 0);
    h2.appendChild(d);
    ShadyDOM.flush();
    assert.equal(h2.childNodes.length, 1);
    assert.equal(h2.firstChild, d);
    assert.equal(h1.childNodes.length, 0);
    assert.deepEqual(h1.$.content.assignedNodes({flatten: true}).length, 0);
    document.body.removeChild(h1);
  });

  test('moving children between distributing host with shallow insertion and fragment (parsed child)', function() {
    var div = document.createElement('div');
    div.innerHTML = '<x-dist-simple><div></div></x-dist-simple>';
    var h1 = div.firstChild;
    var h2 = createPatchedDocumentFragment();
    document.body.appendChild(h1);
    ShadyDOM.flush();
    var d = h1.firstElementChild;
    assert.equal(d.localName, 'div');
    assert.equal(h1.childNodes.length, 1);
    assert.equal(h1.firstElementChild, d);
    assert.deepEqual(h1.$.content.assignedNodes({flatten: true}), [d]);
    assert.equal(h2.childNodes.length, 0);
    h2.appendChild(d);
    ShadyDOM.flush();
    assert.equal(h2.childNodes.length, 1);
    assert.equal(h2.firstChild, d);
    assert.equal(h1.childNodes.length, 0);
    assert.deepEqual(h1.$.content.assignedNodes({flatten: true}).length, 0);
    h1.appendChild(d);
    ShadyDOM.flush();
    assert.equal(h1.childNodes.length, 1);
    assert.equal(h1.firstElementChild, d);
    assert.deepEqual(h1.$.content.assignedNodes({flatten: true}), [d]);
    assert.equal(h2.childNodes.length, 0);
    h2.appendChild(d);
    ShadyDOM.flush();
    assert.equal(h2.childNodes.length, 1);
    assert.equal(h2.firstChild, d);
    assert.equal(h1.childNodes.length, 0);
    assert.deepEqual(h1.$.content.assignedNodes({flatten: true}).length, 0);
    document.body.removeChild(h1);
  });

  test('moving an element containing a dom-repeat that distributes items', function() {
    var x1 = document.createElement('x-repeat');
    var div = document.createElement('div');
    document.body.appendChild(x1);
    document.body.appendChild(div);
    flush();
    assert.equal(x1.$.dist.children.length, 4);

    div.appendChild(x1);
    ShadyDOM.flush();
    assert.equal(x1.$.dist.children.length, 4);

    document.body.appendChild(x1);
    ShadyDOM.flush();
    assert.equal(x1.$.dist.children.length, 4);

    div.appendChild(x1);
    ShadyDOM.flush();
    assert.equal(x1.$.dist.children.length, 4);

    document.body.removeChild(div);
  });

  test('dom-repeat that distributes inside a slot container', function(done) {
    var x1 = document.querySelector('#repeat2');
    ShadyDOM.flush();
    // async due to attachment.
    setTimeout(function() {
      assert.equal(x1.$.dist.children.length, 4);

      done();
    });
  });

  test('adding a document fragment clears nodes in the fragment', function() {
    var x = document.createElement('x-dist-star');
    document.body.appendChild(x);
    var frag = document.createDocumentFragment();
    var t = document.createTextNode('hi');
    var d = document.createElement('div');
    frag.appendChild(t);
    frag.appendChild(d);
    x.appendChild(frag);
    ShadyDOM.flush();
    assert.equal(t.parentNode, x, 'logical parent wrong');
    assert.equal(d.parentNode, x, 'logical parent wrong');
    assert.equal(frag.childNodes.length, 0, 'fragment not empty');
    document.body.removeChild(x);
  });

  test('adding a non-distributing node removes the node from its current location', function() {
    var x = document.createElement('x-dist-star');
    var t = document.createTextNode('hi');
    document.body.appendChild(t);
    x.appendChild(t);
    ShadyDOM.flush();
    assert.equal(t.parentNode, x);

  });

});

suite('multi-content mutations', function() {

  test('remove, append first content', function() {
    var el = document.createElement('x-multi-dist');
    document.body.appendChild(el);
    // Append div
    var div = document.createElement('div');
    el.appendChild(div);
    ShadyDOM.flush();

    // Remove first content
    el.$.dist1.removeChild(el.$.content1);
    ShadyDOM.flush();

    // Re-add a new first content
    el.$.dist1.appendChild(document.createElement('slot'));
    ShadyDOM.flush();

  });

  test('remove, append first distributing element', function() {
    var el = document.createElement('x-multi-dist');
    document.body.appendChild(el);
    // Append div
    var div = document.createElement('div');
    el.appendChild(div);
    ShadyDOM.flush();

    // Remove first element with nested content
    el.root.removeChild(el.$.dist1);
    ShadyDOM.flush();

    // Re-add a new first content
    var frag = document.createDocumentFragment();
    var dist = document.createElement('x-dist');
    dist.appendChild(document.createElement('slot'));
    frag.appendChild(dist);
    el.root.insertBefore(frag, el.$.dist2);
    // Note, special call required here
    ShadyDOM.flush();

  });

  test('move first distributing element', function() {
    var el = document.createElement('x-multi-dist');
    document.body.appendChild(el);
    // Append div
    var div = document.createElement('div');
    el.appendChild(div);
    ShadyDOM.flush();

    // Remove first element with nested content to the end
    el.root.appendChild(el.$.dist1);
    // Note, special call required here
    ShadyDOM.flush();

  });

});

suite('dom-if append <slot>', function() {

  test('x-dynamic-content', function() {
    var el = document.createElement('x-dynamic-content');
    document.body.appendChild(el);
    var div = document.createElement('div');
    div.name = 'insert';
    el.appendChild(div);

    el.$.domif.if = true;
    el.$.domif.render();
    ShadyDOM.flush();

    document.body.removeChild(el);
  });

  test('x-dynamic-content-wrapped', function() {
    var el = document.createElement('x-dynamic-content-wrapped');
    document.body.appendChild(el);
    var div = document.createElement('div');
    div.name = 'insert';
    el.appendChild(div);

    el.$.domif.if = true;
    el.$.domif.render();
    ShadyDOM.flush();

    document.body.removeChild(el);
  });

  test('x-dynamic-content-redist', function() {
    var el = document.createElement('x-dynamic-content-redist');
    document.body.appendChild(el);
    var div = document.createElement('div');
    div.name = 'insert';
    el.appendChild(div);

    el.$.redistDomif.if = true;
    el.$.redistContainer.$.domif.if = true;
    el.$.redistDomif.render();
    ShadyDOM.flush();

    document.body.removeChild(el);
  });

  test('x-dynamic-content-redist-element', function() {
    var el = document.createElement('x-dynamic-content-redist-element');
    document.body.appendChild(el);
    var div = document.createElement('div');
    div.name = 'insert';
    el.appendChild(div);

    el.$.redistDomif.if = true;
    el.$.redistDomif.render();
    ShadyDOM.flush();

    document.body.removeChild(el);
  });

  test('x-toggle-if', function() {
    var el = document.createElement('x-toggle-if');
    document.body.appendChild(el);
    var c1 = document.createElement('div');
    c1.id = 'one';
    el.appendChild(c1);
    var c2 = document.createElement('div');
    c2.id = 'two';
    el.appendChild(c2);
    el.$.foo.render();
    el.$.notFoo.render();
    ShadyDOM.flush();

    el.foo = false;
    el.$.foo.render();
    el.$.notFoo.render();
    ShadyDOM.flush();

    el.foo = true;
    el.$.foo.render();
    el.$.notFoo.render();
    ShadyDOM.flush();

    el.foo = false;
    el.$.foo.render();
    el.$.notFoo.render();
    ShadyDOM.flush();

    el.foo = true;
    el.$.foo.render();
    el.$.notFoo.render();
    ShadyDOM.flush();

    document.body.removeChild(el);
  });

  test('x-dynamic-content-and-dynamic-no-content', function() {
    var el = document.createElement('x-dynamic-content-and-dynamic-no-content');
    document.body.appendChild(el);
    var c1 = document.createElement('div');
    c1.slot = 'one';
    el.appendChild(c1);
    flush();
    assert.equal(el.querySelector('[slot="one"]'), c1);
    assert.notOk(el.root.querySelector('#static'));
    assert.notOk(el.root.querySelector('slot'));
    el.$.contentIf.if = true;
    el.$.staticIf.if = true;
    flush();
    assert.ok(el.root.querySelector('#static'));
    var ip = el.root.querySelector('slot');
    assert.ok(ip);
    assert.equal(ip.assignedNodes({flatten: true})[0], c1);
    el.$.contentIf.if = false;
    el.$.staticIf.if = false;
    flush();
    assert.equal(el.querySelector('[slot="one"]'), c1);
    assert.notOk(el.root.querySelector('#static'));
    assert.notOk(el.root.querySelector('slot'));
    el.$.contentIf.if = true;
    el.$.staticIf.if = true;
    flush();
    assert.ok(el.root.querySelector('#static'));
    ip = el.root.querySelector('slot');
    assert.ok(ip);
    assert.equal(ip.assignedNodes({flatten: true})[0], c1);
    document.body.removeChild(el);
  });

});
</script>

</body>
</html>
